package jp.anago_dev.takarush_helper.map;

import jp.anago_dev.takarush_helper.R;
import jp.anago_dev.takarush_helper.database.DatabaseHelper;
import jp.anago_dev.takarush_helper.database.LocationDatabaseHandler;
import jp.anago_dev.takarush_helper.location.ILocationService;
import jp.anago_dev.takarush_helper.location.IUpdateLocationCallback;
import jp.anago_dev.takarush_helper.location.LastKnownLocationFinder;
import jp.anago_dev.takarush_helper.location.LocationService;
import jp.anago_dev.takarush_helper.net.HttpConnectionListener;
import jp.anago_dev.takarush_helper.net.HttpConnector;
import jp.anago_dev.takarush_helper.net.HttpConnector.Error;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.location.Location;
import android.location.LocationManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;

/**
 * マップのUI以外の処理を行います。<br/>
 * DBの書き込み、現在位置の更新を行います。<br/>
 * TODO:クラスが肥大化した場合は、クラスをLocation、DB、HTTP...etc等に分ける
 * 
 * @author anago_dev
 * 
 */
public final class MapFacade {

    /** コンテキスト */
    private final Context mContext;

    /** {@link ILocationService} */
    private ILocationService mLocationService;

    /** {@link LastKnownLocationFinder} */
    private final LastKnownLocationFinder mLastKnownLocationFinder;

    /** {@link IUpdateLocationCallback} */
    private final IUpdateLocationCallback mCallback;

    /** 位置情報取得サービス接続フラグ */
    private boolean mIsLocationServiceBinding = false;

    /** サービス接続 */
    private final ServiceConnection mLocationServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(final ComponentName name, final IBinder service) {
            mLocationService = ILocationService.Stub.asInterface(service);

            try {
                // コールバックの登録
                mLocationService.registerUpdateLocationCallback(mCallback);
                mIsLocationServiceBinding = true;
            } catch (RemoteException e) {
            }
        }

        /**
         * ※クラッシュ時にコールされます。
         * 
         * @see android.content.ServiceConnection#onServiceDisconnected(android.content.ComponentName)
         */
        @Override
        public void onServiceDisconnected(final ComponentName name) {
            try {
                // コールバックの解除
                mLocationService.unregisterUpdateLocationCallback(mCallback);

            } catch (RemoteException e) {
            }

        }
    };

    /**
     * コンストラクタ
     * 
     * @param callback
     */
    public MapFacade(final Context context, final IUpdateLocationCallback callback) {

        mContext = context;
        mCallback = callback;
        mLastKnownLocationFinder = new LastKnownLocationFinder(mContext);

    }

    /**
     * 位置情報の更新を行います。
     */
    public void startLocationUpdate() {

        // 位置履歴の取得
        try {
            final Location lastKnownLocation = mLastKnownLocationFinder.getLastBestLocation();
            // TODO:テストコード(accurancy)
            if (lastKnownLocation != null) {
                mCallback.updateLocation(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude(), lastKnownLocation.getTime(), 0.0f);
            }
            System.out.println("履歴" + lastKnownLocation);
        } catch (RemoteException e) {
            e.printStackTrace();
        }

        // サービスへのバインド
        Intent intent = new Intent(ILocationService.class.getName());
        intent.putExtra(LocationService.INTENT_KEY_PROVIDER, LocationManager.GPS_PROVIDER);
        intent.putExtra(LocationService.INTENT_KEY_LOCATION_INTERVAL, getLocationUpdateInterval());
        mContext.bindService(intent, mLocationServiceConnection, Context.BIND_AUTO_CREATE);
        mIsLocationServiceBinding = true;

    }

    /**
     * 位置情報の更新を停止を行います。
     */
    public void stopLocationUpdate() {
        try {
            // サービスの停止
            if (mLocationService != null) {
                mLocationService.stopService();
            }
        } catch (RemoteException e) {
        } finally {
            if (mIsLocationServiceBinding) {
                // バインド解除
                mContext.unbindService(mLocationServiceConnection);
                mIsLocationServiceBinding = false;
            }
        }
    }

    /**
     * 位置情報をDBに保存します。
     * 
     * @param db
     * @param latitude
     * @param longitude
     * @param time
     * @param accuracy
     */
    public void insertLocationData(final double latitude, final double longitude, final long time, final float accuracy) {

        final SQLiteDatabase db = DatabaseHelper.getInstance(mContext).getWritableDatabase();
        LocationDatabaseHandler.insert(db, latitude, longitude, time, accuracy);

    }

    /**
     * バインド状態か返します。
     * 
     * @return
     */
    public boolean isLocationServiceBinding() {
        return mIsLocationServiceBinding;
    }

    /**
     * プリファレンスから更新間隔を取得します。
     * 
     * @return 更新間隔(記録がなければ
     *         {@link LocationService#DEFAULT_LOCATION_UPDATE_INTERVAL})
     */
    private int getLocationUpdateInterval() {

        final String defaultValue = "-1";

        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        String interval = sharedPreferences.getString(mContext.getString(R.string.key_location_update_interval), defaultValue);

        return interval.equals(defaultValue) ? LocationService.DEFAULT_LOCATION_UPDATE_INTERVAL : Integer.parseInt(interval);

    }

    /**
     * TODO:通信のテストコードです。
     */
    public void connectionTest() {
        new HttpConnector(new HttpConnectionListener() {

            @Override
            public void onComplete(JSONObject jsonObject) {
                try {
                    // JSON解析
                    JSONArray jsonArray = jsonObject.getJSONArray("Google");
                    int length = jsonArray.length();
                    for (int i = 0; i < length; i++) {
                        System.out.println(jsonArray.getString(i));
                    }
                } catch (JSONException e) {
                    onFail(Error.ERROR_JSON_PARSE);
                }

            }

            @Override
            public void onFail(HttpConnector.Error error) {
                System.out.println("失敗:" + error.name());
            }
        }).execute();

    }

}
